home *** CD-ROM | disk | FTP | other *** search
- /* object.c
- *
- * Functions for displaying and manipulting objects
- */
- #include "net3d.h"
-
- double gtm=0.0; /* total time elapsed since */
- /* start of game */
-
- int vidcount=0; /* total number of vehicles */
- /* created so far */
-
- double vmax[TYPECOUNT]={79,35,25, /* maximum velocities for the */
- 1000,0,1000, /* different vehicle types. */
- 150,0,200, /* used if no maximum is given */
- 0,100,0,
- 200,0,0,};
-
- /* The extra vehicles/objects list is used for storing objects
- * created in-game, such as bullets, walls and new trees. It also
- * stores vehicle definitions made in the vehicle files, for later
- * instantiation.
- */
- struct vehicle *evhead; /* head of the extra vehicles list */
- struct object *eohead; /* head of the extra objects list */
-
- vehicle_type playertype; /* vehicle type of player when
- * they are wandering around on foot */
-
- /* prints stats about the world */
- void worldinfo(struct vehicle *vhead, struct object *ohead)
- {
- int vc=0; /* vehicles */
- int oc=0; /* objects */
- int fc=0; /* faces */
- int pc=0; /* points */
-
- for(vc=0; vhead; vhead=vhead->next,vc++)
- ;
- for(oc=0; ohead; ohead=ohead->next,oc++) {
- fc += ohead->fcount;
- pc += ohead->pcount;
- }
- printf("%d vehicles\n%d objects\n%d faces\n%d points\n",vc,oc,fc,pc);
- }
-
- /* prints the vehicle list on screen (debugging purposes only) */
- void dumpvehicles(struct vehicle *vhead)
- {
- int vc=0;
-
- for(;vhead;vhead=vhead->next) {
- struct object *obj;
- int oc;
-
- printf("\nvehicle %d\n",vc++);
- printf("\tpartcount=%d\n",vhead->partcount);
- printf("\tname=%s\n",vhead->name);
- printf("\tcode=%s\n",vhead->code);
- printf("\tangle=%f\n",vhead->angle);
- printf("\tvelocity=%f\n",vhead->velocity);
-
- printf("\tb-box %f %f %f to %f %f %f\n",vhead->bmin.x,
- vhead->bmin.y,vhead->bmin.z,vhead->bmax.x,vhead->bmax.y,
- vhead->bmax.z);
-
- for(oc=0;oc < vhead->partcount;oc++) {
- int i;
-
- obj=vhead->parts[oc];
- printf("\n\t\tobject %d\n",oc);
- printf("\t\tpcount=%d fcount=%d\n",obj->pcount,obj->fcount);
- printf("\t\tpos=%f %f %f\n",obj->pos.x,obj->pos.y,
- obj->pos.z);
- printf("\t\tcent=%f %f %f\n",obj->cent.x,obj->cent.y,
- obj->cent.z);
- printf("\t\tdist=%f\n",obj->dist);
-
- printf("\t\tpoints : ");
- for(i=0;i < obj->pcount;i++)
- printf("%f %f %f ",obj->points[i].x,
- obj->points[i].y,obj->points[i].z);
- printf("\n");
-
- printf("\t\tfaces : ");
- for(i=0;i < obj->fcount;i++) {
- struct polygon *pol;
- int j;
-
- pol=obj->faces+i;
- printf("\n\t\t\tface %d\n",i);
- printf("\t\t\tpcount=%d\n",pol->pcount);
- printf("\t\t\tcolour=%ld\n",pol->colour);
- printf("\t\t\ttype=%d\n",pol->type);
- printf("\t\t\tpoints : ");
- for(j=0;j < pol->pcount;j++)
- printf("%d ",pol->vertices[j]);
- printf("\n");
- }
- }
- }
- }
-
- /* movevehicle - moves all the parts of a vehicle the distance they
- * should move in a given time
- *
- * v - vehicle to move
- * tm - travel time
- */
- void movevehicle(struct vehicle *v, double tm, struct map *mp)
- {
- int i;
- struct object **ob;
- float xd,yd; /* direction of travel */
- float xv,yv,zv=0.0; /* travel movement */
- double rotz=0.0; /* rotation of vehicle */
- struct point vcen;
- int mx,my; /* map position */
- float ht; /* height at that position */
- bool changed=false; /* has bounding box changed */
- float mxf, myf;
-
- ob=v->parts;
- vcen=ob[0]->pos;
- /* find position on map, and height at that point
- */
- xd=jcos(v->angle); yd=jsin(v->angle);
- if (mp->size) {
- mx = mxf = (vcen.x + (xd*20))/mp->size;
- my = myf = (vcen.y + (yd*20))/mp->size;
- if (mxf >= 0 && myf >= 0 && mx<mp->map_w && my<mp->map_h)
- ht = mp->ht[mx][my];
- else
- ht = 0.0;
- }
- else {
- ht = 0.0;
- }
-
- /* move forward, and drop down towards ground */
- if ((v->velocity || v->climb || vcen.z!=ht) && v->type!=t_scenery) {
- xv=xd*tm*v->velocity;
- yv=yd*tm*v->velocity;
- zv=tm*v->climb;
- if (mp->ground && !v->flying && vcen.z>0)
- v->climb -= tm*GRAVITY; /* fall to earth */
- if (vcen.z < 0 && mp->ground) { /* keep above ground level */
- zv = -vcen.z;
- }
- else if (vcen.z > v->max.altitude) { /* .. and below ceiling */
- zv = v->max.altitude-vcen.z;
- v->climb = 0.0;
- }
- shiftvehicle(v,xv,yv,zv);
- /* if there is a maximum range, decrease and explode when
- * range limit is reached.
- */
- if (v->range) {
- v->range -= tm*(dabs(v->velocity) + dabs(v->climb));
- if (v->range < 0)
- v->hp = -1;
- }
- }
-
- /* slow down turn rate.
- * NOTE!! - this can probably be removed.
- */
- if (v->owner == o_player || v->owner == o_network) {
- if (v->angle_vel > 0) {
- v->angle_vel -= tm*dtor(FRICTION);
- if (v->angle_vel < 0)
- v->angle_vel = 0;
- }
- else if (v->angle_vel < 0) {
- v->angle_vel += tm*dtor(FRICTION);
- if (v->angle_vel > 0)
- v->angle_vel = 0;
- }
-
- /* slow down turret turn rate */
- for(i=0; i<v->partcount; i++) {
- if (v->parts[i]->turret) {
- if (v->parts[i]->angle_vel > 0) {
- v->parts[i]->angle_vel -= tm*dtor(FRICTION);
- if (v->parts[i]->angle_vel < 0)
- v->parts[i]->angle_vel = 0;
- }
- else if (v->parts[i]->angle_vel < 0) {
- v->parts[i]->angle_vel += tm*dtor(FRICTION);
- if (v->parts[i]->angle_vel > 0)
- v->parts[i]->angle_vel = 0;
- }
- }
- }
- }
-
- /* rotate all parts of the vehicle.
- * rotation is angle_vel radians per second.
- */
- if (v->angle_vel != 0) {
- changed=true;
- rotz=tm*v->angle_vel;
- v->angle += rotz;
- if (v->angle < 0) /* keep angle within */
- v->angle += 2*PI; /* 0 - 2PI */
- else if (v->angle > 2*PI)
- v->angle -= 2*PI;
- for(i=0; i < v->partcount; i++)
- rotatez(v->parts[i],rotz);
- }
-
-
- /* rotate separate sections as well (ie gun turrets) */
- for(i=0; i<v->partcount; i++) {
- v->parts[i]->angle += rotz;
- if (v->parts[i]->angle_vel) {
- double rotz2; /* rotation for part */
-
- changed=true;
- rotz2=tm*v->parts[i]->angle_vel;
- rotatez(v->parts[i],rotz2);
- v->parts[i]->angle += rotz2;
- }
- }
-
- /* check for collision with ground hills, or with the ground if
- * there is any.
- */
- if (vcen.z < ht && (ht != 0.0 || mp->ground)) {
- /* if a mountain has been hit, bounce back a bit */
- if (v->type == t_bullet || v->type == t_shrapnel ||
- v->type == t_seedpod) {
- /* Some things are always destroyed on impact with
- * the ground or a hill. */
- v->hp = -1;
- }
- else {
- if (ht) {
- /* impact with a hill */
- shiftvehicle(v,-xv*2,-yv*2,0);
- v->hp -= (v->velocity < 5) ? 0 : 5;
- }
- else {
- /* impact with the ground */
- v->hp -= 5;
- }
- v->velocity = 0.0;
- v->climb = 0.0;
- v->angle_vel = 0.0;
- v->bumped = True;
- }
- }
-
- /* apply oscillation vectors */
- for(i=0; i<v->partcount; i++) {
- int j;
- struct object *ob;
- ob=v->parts[i];
- for(j=0; j<ob->ocount; j++) {
- float osc; /* amount oscillated (0-1) */
- osc=ob->oscli[j].func(gtm*ob->oscli[j].rate +
- ob->oscli[j].phase);
- if (ob->oscli[j].axes & OSC_X_AXIS)
- ob->oscli[j].pt->x = ob->oscli[j].init.x +
- ob->oscli[j].ovec.x*osc;
- if (ob->oscli[j].axes & OSC_Y_AXIS)
- ob->oscli[j].pt->y = ob->oscli[j].init.y +
- ob->oscli[j].ovec.y*osc;
- if (ob->oscli[j].axes & OSC_Z_AXIS)
- ob->oscli[j].pt->z = ob->oscli[j].init.z +
- ob->oscli[j].ovec.z*osc;
- changed=true;
- }
- }
-
- /* apply spin factors */
- if (v->xspin_vel) {
- for(i=0; i < v->partcount; i++)
- rotatex(v->parts[i],tm*v->xspin_vel);
- changed=true;
- }
- if (v->yspin_vel) {
- for(i=0; i < v->partcount; i++)
- rotatey(v->parts[i],tm*v->yspin_vel);
- changed=true;
- }
- if (v->zspin_vel) {
- for(i=0; i < v->partcount; i++)
- rotatez(v->parts[i],tm*v->zspin_vel);
- changed=true;
- }
-
-
-
- /* slow down climb/dive, if appropriate.
- */
- if (v->flying && v->type != t_bullet && v->type != t_shrapnel) {
- if (v->climb > 0) {
- v->climb -= tm*70;
- if (v->climb < 0)
- v->climb = 0;
- }
- if (v->climb < 0) {
- v->climb += tm*70;
- if (v->climb > 0)
- v->climb = 0;
- }
- }
-
- /* decrease reload time */
- if (v->reload > 0)
- v->reload -= tm;
-
- /* increase time since last hit */
- if (v->lasthit >= 0)
- v->lasthit += tm;
-
- /* decrease timer used in brain */
- if (v->ftimer >= 0)
- v->ftimer -= tm;
-
- /* re-calculate bounding box if object has been rotated, oscillated
- * or spun, changing the points */
- if (changed)
- calcbbox(v);
- }
-
- void movevehicles(struct vehicle **vh, struct object **oh, struct map *mp,
- double gtime)
- {
- static double ctime=0.0; /* time at last call */
- double ntime; /* time for this call */
- struct vehicle *v,*va,*vb;
- int tmp;
- double tm;
- struct vehicle *vnext;
-
- /* find time since last movevehicles, from time passed in as parameter.
- * This time comes from the server, making sure that all clients are
- * synchronised.
- */
- if (!ctime) {
- ctime=gtime;
- return;
- }
- ntime=gtime;
- tm = ntime-ctime; /* time to move for this call */
-
- /* check for vehicle-vehicle collisions. */
- for(va=*vh; va; va=vnext) {
- vnext = va->next;
- if ((vb = collide(va,*vh))) {
- /* check for transfer to another vehicle. */
- if (enteredvehicle(va,vb)) {
- /* va has entered vb */
- va->transfer = vb->vid;
- vb->owner = o_network;
- vb->res = va->res;
- vb->pnum = va->pnum;
- freevehicle(va,vh,oh);
- continue;
- }
- if (enteredvehicle(vb,va)) {
- /* vb has entered va */
- vb->transfer = va->vid;
- va->owner = o_network;
- va->res = vb->res;
- va->pnum = vb->pnum;
- freevehicle(vb,vh,oh);
- continue;
- }
-
- /* check for resource collection */
- if (va->type == playertype && vb->type == t_tree) {
- va->res += 5;
- freevehicle(vb,vh,oh);
- continue;
- }
- if (vb->type == playertype && va->type == t_tree) {
- vb->res += 5;
- freevehicle(va,vh,oh);
- continue;
- }
-
- /* check for collecting a bonus item */
- if (va->type == t_weapon && (vb->owner == o_player ||
- vb->owner == o_network)) {
- vb->weapon = va->weapon;
- freevehicle(va,vh,oh);
- continue;
- }
- if (vb->type == t_weapon && (va->owner == o_player ||
- va->owner == o_network)) {
- va->weapon = vb->weapon;
- freevehicle(vb,vh,oh);
- continue;
- }
-
- /* check for collecting a munitions bonus */
- if (va->type == t_munitions && (vb->owner == o_player ||
- vb->owner == o_network)) {
- vb->ammo += va->ammo;
- freevehicle(va,vh,oh);
- continue;
- }
- if (vb->type == t_munitions && (va->owner == o_player ||
- va->owner == o_network)) {
- va->ammo += va->ammo;
- freevehicle(va,vh,oh);
- continue;
- }
-
- /* damage both */
- tmp = va->hp;
- va->hp -= vb->hp;
- vb->hp -= tmp;
-
- /* record last hit time */
- if (vb->type == t_bullet || vb->type == t_missile)
- va->lasthit = 0.0;
- else
- va->bumped = True;
- if (va->type == t_bullet || va->type == t_missile)
- vb->lasthit = 0.0;
- else
- vb->bumped = True;
-
- /* halt both vehicles, except for those that have been
- * hit by a bullet.
- */
- if (vb->type != t_bullet) {
- va->velocity=0.0;
- va->angle_vel=0.0;
- }
- if (va->type != t_bullet) {
- vb->velocity=0.0;
- vb->angle_vel=0.0;
- }
-
- /* If a bullet hits something, make sure that it is
- * destroyed.
- */
- if (va->type==t_bullet || va->type==t_missile ||
- va->type == t_mine)
- va->hp = -1;
- if (vb->type==t_bullet || vb->type==t_missile ||
- vb->type == t_mine)
- vb->hp = -1;
-
- /* kludge - if two vehicles with equal hp collide, then make
- * them both explode, otherwise they will both end up on
- * hp 0, and have no further effect on each other.
- */
- if (!va->hp && !vb->hp) {
- va->hp = vb->hp = -1;
- }
- /*
- printf("%s has hit %s\n", va->code,vb->code);
- */
- }
- }
-
- /* apply move to all vehicles, except for static and scenery types */
- for(v=*vh; v; v = vnext) {
- vnext = v->next;
- if (v->type != t_scenery && v->type != t_static && v->type != t_mine)
- movevehicle(v,tm,mp);
- if (v->hp < 0) {
- if (v->type == t_tree) {
- /* If a tree is hit by something, then change it's
- * type to static, so that it doesn't explode into
- * seedpods.
- */
- v->type = t_static;
- }
- explode(vh,oh,v);
- }
- }
-
- /* increment game time, and store current time for this call */
- gtm += ntime-ctime;
- ctime=ntime;
- }
-
- void multpoints(struct object *ob, float mat[3][3])
- {
- struct point src;
- int i;
-
- /* multiply points */
- for(i=0; i < ob->pcount; i++) {
- src=ob->points[i];
- mmult(&src,mat,ob->points+i);
- }
-
- /* multiply centre */
- src=ob->cent;
- mmult(&src,mat,&ob->cent);
-
- /* multiply oscillation vectors, except for those applying to the
- * position of an object instead of one of it's points.
- */
- for(i=0; i<ob->ocount; i++) {
- if (ob->oscli[i].pt != &ob->pos) {
- src=ob->oscli[i].init;
- mmult(&src,mat,&(ob->oscli[i].init));
- }
- src=ob->oscli[i].ovec;
- mmult(&src,mat,&(ob->oscli[i].ovec));
- }
- }
-
- void rotatez(struct object *ob, double rad)
- {
- float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
-
- rotm[0][0]=(float)jcos(rad); rotm[1][0]=(float)jsin(rad);
- rotm[0][1]=-rotm[1][0]; rotm[1][1]=rotm[0][0];
- multpoints(ob,rotm);
- }
-
- void rotatex(struct object *ob, double rad)
- {
- float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
-
- rotm[1][1]=(float)jcos(rad); rotm[2][1]=(float)jsin(rad);
- rotm[1][2]=-rotm[2][1]; rotm[2][2]=rotm[1][1];
- multpoints(ob,rotm);
- }
-
- void rotatey(struct object *ob, double rad)
- {
- float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
-
- rotm[0][0]=(float)jcos(rad); rotm[2][0]=(float)-jsin(rad);
- rotm[0][2]=-rotm[2][0]; rotm[2][2]=rotm[0][0];
- multpoints(ob,rotm);
- }
-
- double gametime(void)
- {
- struct timeval tv;
- struct timezone tz;
- gettimeofday(&tv,&tz);
- return tv.tv_sec+tv.tv_usec/1000000.0;
- }
-
-
- void makemap(struct object **ohead, struct map *mp)
- {
- int i,j;
-
- /* generate ground objects (map starts at 0,0).
- */
- for(i=0; i<mp->map_w; i++)
- for(j=0; j<mp->map_h; j++) {
- float c0,c1,c2,c3; /* corner heights */
- struct point ps,ct;
- struct point pts[4];
- int facepts[4]={0,1,3,2};
- struct polygon fcs[1]={{4,NULL,0,f_plane}};
-
- /* heights at each polygon corner are the average of */
- /* the heights of surrounding polygons */
- c0=calcmap(i,j,mp);
- c1=calcmap(i,j+1,mp);
- c2=calcmap(i+1,j+1,mp);
- c3=calcmap(i+1,j,mp);
- mp->ht[i][j]=(c0+c1+c2+c3)/4.0; /* average polygon height */
- if (mp->ht[i][j] == 0)
- /* zero height */
- continue;
-
- /* each ground square is a single rectangle */
- /* position */
- ps.x=i*mp->size;
- ps.y=j*mp->size;
- ps.z=0.0;
- /* centre */
- ct.x=mp->size/2;
- ct.y=mp->size/2;
- ct.z=0.0;
- /* points */
- pts[0].x=0; pts[0].y=0; pts[0].z=c0;
- pts[1].x=mp->size; pts[1].y=0; pts[1].z=c3;
- pts[2].x=0; pts[2].y=mp->size; pts[2].z=c1;
- pts[3].x=mp->size; pts[3].y=mp->size; pts[3].z=c2;
- /* faces */
- fcs[0].vertices=facepts;
- fcs[0].colour=(mp->tcol*32)+31-(mp->gr[i][j]/mp->scale)*31;
- addobject(ohead,ps,ct,NULL,4,1,pts,fcs);
- (*ohead)->mx = i;
- (*ohead)->my = j;
- }
- }
-
- struct object *addobject(struct object **ohead, struct point pos, struct
- point cent, struct vehicle *par, int pc, int fc, struct point *pts, struct
- polygon *fcs)
- {
- struct object *no;
- int i;
-
- /* make a new object, containing deep copies of all the points/faces
- * passed in as parameters */
- no=(struct object *)calloc(1,sizeof(struct object));
- no->next=(*ohead);
- (*ohead)=no;
- no->pcount=pc;
- no->fcount=fc;
- no->points=(struct point *)calloc(pc,sizeof(struct point));
- no->cpoints=(struct point *)calloc(pc,sizeof(struct point));
- no->ppoints=(XPoint *)calloc(pc,sizeof(XPoint));
- memcpy(no->points,pts,pc*sizeof(struct point));
- no->faces=(struct polygon *)calloc(fc,sizeof(struct polygon));
- for(i=0; i<fc; i++) {
- no->faces[i].pcount=fcs[i].pcount;
- no->faces[i].colour=fcs[i].colour;
- no->faces[i].type=fcs[i].type;
- no->faces[i].vertices=calloc(fcs[i].pcount,sizeof(int));
- memcpy(no->faces[i].vertices,fcs[i].vertices,fcs[i].pcount*
- sizeof(int));
- }
- no->pos=pos;
- no->cent=cent;
- no->dist=0.0;
- no->parent=par;
- no->clockwise=true;
- no->cvalid = false;
- no->mightsave = false;
- return no;
- }
-
- /* calculates the height of the bottom-left corner of map square x,y */
- float calcmap(int x, int y, struct map *m)
- {
- float sum=0.0;
- sum += (x < m->map_w && y < m->map_h ? m->gr[x][y] : 0.0);
- sum += (x > 0 && y < m->map_h ? m->gr[x-1][y] : 0.0);
- sum += (x > 0 && y > 0 ? m->gr[x-1][y-1] : 0.0);
- sum += (x < m->map_w && y > 0 ? m->gr[x][y-1] : 0.0);
- return sum/4.0;
- }
-
-
- /* explode - removes a vehicle from the game, possibly with a large
- * explosion of shrapnel and several flaming fireballs.
- *
- * vhead - pointer to the head of the vehicle list
- * ohead - pointer to the head of the object list
- * t - the vehicle to explode
- */
- void explode(struct vehicle **vhead, struct object **ohead, struct
- vehicle *t)
- {
- int i,j;
- struct point vcen;
-
- /*
- printf("exploding %s\n",t->code);
- */
- vcen=t->parts[0]->pos; /* get position of vehicle */
-
- if (t->type != t_shrapnel && t->type != t_seedpod) {
- /* create blast fragments */
- for(i=0; i<t->partcount; i++) {
- int j;
- struct object *ob;
-
- ob=t->parts[i];
- for(j=0; j<ob->fcount; j++) {
- struct vehicle *nv;
- struct point pts[MAX_POINTS_PER_OBJECT];
- struct polygon fcs[1];
- int facepts[MAX_POINTS_PER_FACE];
- int pc,k;
- struct point pos;
- struct point cent={0,0,0};
-
- /* create a new vehicle structure */
- nv=(struct vehicle *)calloc(1,sizeof(struct vehicle));
- nv->next=(*vhead); /* add to list */
- *vhead=nv;
- nv->partcount = 1;
- nv->owner = o_game;
- if (t->type == t_tree && rand()%SEEDCHANCE == 0)
- nv->type = t_seedpod;
- else
- nv->type = t_shrapnel;
- nv->weapon = w_none;
- nv->flying = false;
- nv->code = strdupe("shrapnel");
- nv->name = strdupe("a blast fragment");
- nv->velocity = rand()%40;
- nv->climb = (rand()%60)-20;
- nv->angle = dtor(rand()%360);
- nv->hp = 1;
- nv->alive = true;
- nv->vid = vidcount++;
- nv->parts = (struct object **)
- calloc(1,sizeof(
- struct object *));
- nv->max.velocity = MAX_VELOCITY;
- nv->max.angle_vel = MAX_ANGLE_VEL;
- nv->max.altitude = MAX_ALTITUDE;
- nv->transfer = -1;
- nv->buildervid = -1;
- nv->seed = strdupe(t->seed);
- nv->pnum = -1;
- nv->range = 200;
- nv->stcount = 0;
- nv->states = NULL;
- nv->currentstate = -1;
- nv->lasthit = 0.0;
-
- /* extract the points from the original object
- * which are used in the fragment.
- */
- for(pc=0; pc<ob->faces[j].pcount; pc++) {
- facepts[pc] = pc;
- pts[pc] = ob->points[ob->faces[j].
- vertices[pc]];
- }
- fcs[0].pcount=pc;
- fcs[0].vertices=facepts;
- fcs[0].colour=ob->faces[j].colour;
- fcs[0].type=ob->faces[j].type;
-
- /* change points in new object so that the
- * minimum point is at 0,0,0
- */
- pos=pts[0];
- for(k=0; k<pc; k++) {
- if (pos.x < pts[k].x)
- pos.x=pts[k].x;
- if (pos.y < pts[k].y)
- pos.y=pts[k].y;
- if (pos.z < pts[k].z)
- pos.z=pts[k].z;
- }
- for(k=0; k<pc; k++) {
- pts[k].x -= pos.x;
- pts[k].y -= pos.y;
- pts[k].z -= pos.z;
- }
- /* add the initial position of the victim to
- * the position of the fragment.
- */
- pos.x += ob->pos.x;
- pos.y += ob->pos.y;
- pos.z += ob->pos.z + 5;
-
- /* give the fragment a random spin factor */
- nv->xspin_vel = dtor(rand()%20);
- nv->yspin_vel = dtor(rand()%20);
- nv->zspin_vel = dtor(rand()%20);
-
- /* create fragment object, which is one part of */
- /* the original object */
- nv->parts[0]=addobject(ohead,pos,cent,nv,pc,1,pts,fcs);
- }
- }
- }
-
- /* create several flaming fireballs when a vehicle explodes.
- */
- if (t->type == t_tank || t->type == t_hover || t->type == t_fixedwing ||
- t->type == t_gunsite || t->type == t_mine) {
- for(i=0; i<FIREBALLS; i++) {
- struct vehicle *nv;
- char firename[15];
-
- /* create the new fireball vehicle structure.
- */
- nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
- nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
- sizeof(struct object *));
- nv->next = *vhead;
- *vhead = nv;
-
- /* copy a fireball from the extra vehicles list.
- */
- sprintf(firename,"fireball%d",rand()%7 + 25);
- copyvehicle(nv,findbycode(evhead,firename),ohead);
-
- /* set attributes */
- nv->code = strdupe("fireball");
- nv->velocity = rand()%35;
- nv->climb = (rand()%60)-20;
- nv->angle = dtor(rand()%360);
- nv->firer = NULL;
- nv->vid = vidcount++;
- nv->alive = true;
- nv->range = 200;
-
- /* position it near the dead vehicle */
- for(j=0; j<nv->partcount; j++) {
- addpts(nv->parts[j]->pos,t->parts[0]->pos,
- &nv->parts[j]->pos);
- nv->parts[j]->pos.z += 5;
- }
- calcbbox(nv);
- }
- }
-
- /* create new trees when a seedpod hits the ground.
- */
- if (t->type == t_seedpod) {
- /* This is a seedpod. Create a tree at this spot.
- */
- struct vehicle *nv;
- int i;
- struct point pos;
- struct vehicle *seedv;
-
- nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
- nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
- sizeof(struct object *));
- nv->next = *vhead;
- *vhead = nv;
-
- /* Copy the tree object */
- seedv = findbycode(evhead,t->seed);
- copyvehicle(nv,seedv,ohead);
- nv->code=strdupe(seedv->code);
-
- /* position it at the impact point of the seedpod */
- pos = t->parts[0]->pos;
- for(i=0; i<nv->partcount; i++) {
- nv->parts[i]->pos.x += pos.x;
- nv->parts[i]->pos.y += pos.y;
- if (pos.z > 0)
- nv->parts[i]->pos.z += pos.z;
- }
-
- /* set new tree's attributes */
- nv->alive = true;
- nv->vid = vidcount++;
- calcbbox(nv);
- }
-
- freevehicle(t,vhead,ohead);
- }
-
- void freevehicle(struct vehicle *t, struct vehicle **vhead, struct
- object **ohead)
- {
- int i,j;
- struct object **opos;
- struct vehicle **vpos;
-
- for(vpos=vhead; *vpos != t; vpos=&((*vpos)->next))
- ; /* find pointer to to victim on list */
- *vpos=t->next; /* route list around it */
-
- /* free up all vehicle's objects */
- for(i=0; i<t->partcount; i++) {
- for(opos=ohead; *opos != t->parts[i]; opos=&((*opos)->next))
- ; /* find pointer to object on list */
- *opos=t->parts[i]->next; /* re-route list */
- /* free all the point lists of the polygons of the object */
- for(j=0; j<t->parts[i]->fcount; j++) {
- free(t->parts[i]->faces[j].vertices);
- }
- /* free the polygons of the object */
- free(t->parts[i]->faces);
- /* free oscillators */
- free(t->parts[i]->oscli);
- /* free points */
- free(t->parts[i]->points);
- free(t->parts[i]->cpoints);
- free(t->parts[i]->ppoints);
- free(t->parts[i]); /* free object */
- }
-
- /* free up the vehicle's brain */
- for(i=0; i<t->stcount; i++) {
- free(t->states[i].links);
- }
- if (t->states)
- free(t->states);
-
- /* totally free vehicle */
- free(t->name);
- free(t->parts);
- free(t->code);
- if (t->seed)
- free(t->seed);
-
- if (t->owner != o_player) {
- free(t);
- }
- else
- t->alive=false;
- }
-
- /* calculate the bounding box for a single vehicle, by finding the
- * minimum and maximum x,y and z values for that vehicle's points
- */
- void calcbbox(struct vehicle *v)
- {
- int i,j;
- struct object *ob;
- struct point pt;
-
- /* initial min&max from first point in first object */
- ob=v->parts[0];
- v->bmax.x = v->bmin.x = ob->points[0].x + ob->pos.x;
- v->bmax.y = v->bmin.y = ob->points[0].y + ob->pos.y;
- v->bmax.z = v->bmin.z = ob->points[0].z + ob->pos.z;
-
- /* loop through all points, and find min&max x,y & z values */
- for(i=0; i<v->partcount; i++) {
- ob=v->parts[i];
- for(j=0; j<ob->pcount; j++) {
- pt.x = ob->points[j].x + ob->pos.x;
- pt.y = ob->points[j].y + ob->pos.y;
- pt.z = ob->points[j].z + ob->pos.z;
- /* find min & max x */
- if (pt.x < v->bmin.x)
- v->bmin.x=pt.x;
- else if (pt.x > v->bmax.x)
- v->bmax.x=pt.x;
- /* ditto for y */
- if (pt.y < v->bmin.y)
- v->bmin.y=pt.y;
- else if (pt.y > v->bmax.y)
- v->bmax.y=pt.y;
- /* and for z */
- if (pt.z < v->bmin.z)
- v->bmin.z=pt.z;
- else if (pt.z > v->bmax.z)
- v->bmax.z=pt.z;
- }
- }
- }
-
- /* calculate bounding boxes for the whole vehicle list */
- void calcbboxes(struct vehicle *vhead)
- {
- for(; vhead; vhead=vhead->next)
- calcbbox(vhead);
- }
-
- void shiftvehicle(struct vehicle *v, float x, float y, float z)
- {
- int i;
-
- #if 1
- for(i=0; i<v->partcount; i++) {
- /* shift object positions */
- v->parts[i]->pos.x += x;
- v->parts[i]->pos.y += y;
- v->parts[i]->pos.z += z;
- }
- #endif
- /* shift bounding box */
- v->bmin.x += x;
- v->bmin.y += y;
- v->bmin.z += z;
- v->bmax.x += x;
- v->bmax.y += y;
- v->bmax.z += z;
- }
-
- void fire(struct vehicle **vhead, struct object **ohead, struct vehicle *f)
- {
- struct vehicle *nv;
- struct point pos;
- struct object *tur;
- int i;
-
- if (f->weapon==w_none || f->reload > 0 || !f->ammo)
- return;
-
- f->ammo--; /* decrease ammunition */
-
- /* create a new vehicle structure, and add it to the list.
- */
- nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
- nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
- sizeof(struct object *));
- nv->next = *vhead;
- *vhead = nv;
- nv->range=2000.0;
-
- switch(f->weapon) {
- case w_tracer:
- copyvehicle(nv,findbycode(evhead,"tracer"),ohead);
- nv->code=strdupe("tracer");
- nv->velocity = max(f->velocity,0)+200;
- f->reload = 0.3;
- break;
- case w_shell:
- copyvehicle(nv,findbycode(evhead,"shell"),ohead);
- nv->code = strdupe("shell");
- nv->velocity = max(f->velocity,0)+100;
- f->reload = 1.0;
- break;
- case w_bomb:
- copyvehicle(nv,findbycode(evhead,"bomb"),ohead);
- nv->code = strdupe("bomb");
- nv->velocity = f->velocity;
- f->reload = 1.0;
- break;
- case w_bullet:
- copyvehicle(nv,findbycode(evhead,"bullet"),ohead);
- nv->code = strdupe("bullet");
- nv->velocity = max(f->velocity,0)+150;
- f->reload = 0.2;
- break;
- case w_flame:
- copyvehicle(nv,findbycode(evhead,"flame"),ohead);
- nv->code = strdupe("flame");
- nv->velocity = max(f->velocity,0)+100;
- nv->range = 500;
- f->reload = 2.5;
- break;
- case w_missile:
- copyvehicle(nv,findbycode(evhead,"missile"),ohead);
- nv->code = strdupe("missile");
- nv->velocity = max(f->velocity,0)+100;
- f->reload = 3.3;
- /* follow vehicle locked onto by firer */
- if (f->lock == -1)
- nv->target = -2;
- else
- nv->target = f->lock;
- break;
- case w_chicken:
- copyvehicle(nv,findbycode(evhead,"chicken"),ohead);
- nv->code = strdupe("chicken");
- nv->velocity = max(f->velocity,0)+150;
- f->reload = 3.0;
- break;
- case w_plasmaballs:
- copyvehicle(nv,findbycode(evhead,"plasmaballs"),ohead);
- nv->code = strdupe("plasmaballs");
- nv->velocity = max(f->velocity,0)+200;
- f->reload = 1.0;
- break;
- case w_torpedo:
- copyvehicle(nv,findbycode(evhead,"torpedo"),ohead);
- nv->code = strdupe("torpedo");
- nv->velocity = max(f->velocity,0)+100;
- f->reload = 4.0;
- /* follow vehicle locked onto by firer */
- if (f->lock == -1)
- nv->target = -2;
- else
- nv->target = f->lock;
- break;
- case w_none:
- /* no weapon */
- break;
- }
-
- /* set attributes of new projectile */
- nv->owner=o_game;
- nv->weapon=w_none;
- nv->firer=f;
- nv->alive=true;
- nv->vid=vidcount++;
-
- /* store missile's vid in firer */
- f->missile = nv->vid;
-
- /* find firing angle and fire position */
- tur = findturret(f);
- if (tur) {
- nv->angle = tur->angle;
- addpts(tur->pos,tur->cent,&pos);
- }
- else {
- nv->angle=f->angle;
- addpts(f->parts[0]->pos, f->parts[0]->cent,&pos);
- }
-
- /* add the firing position to all objects in the projectile vehicle */
- for(i=0; i<nv->partcount; i++) {
- nv->parts[i]->pos.x += pos.x;
- nv->parts[i]->pos.y += pos.y;
- nv->parts[i]->pos.z += pos.z;
- }
-
- /* add climb to projectile, so that it rises at the correct rate. */
- nv->climb = tan(f->turret_ang)*nv->velocity;
-
- /* rotate projectile to correct angle */
- for(i=0; i<nv->partcount; i++) {
- rotatey(nv->parts[i],-(f->turret_ang));
- rotatez(nv->parts[i],nv->angle);
- }
- calcbbox(nv);
- }
-
- double dabs(double x)
- {
- return (x > 0 ? x : -x);
- }
-
- /* returns the square of the sin of it's argument */
- double sinsq(double x)
- {
- double s;
- s=jsin(x);
- return s*s;
- }
-
- /* returns the sin of it's argument, scaled from 0 to 1 */
- double sinhalf(double x)
- {
- return (jsin(x)+1.0)/2.0;
- }
-
- /* Read the array of strings in extras.c, and send them through a pipe to
- * readfiles().
- */
- void readextravehicles(void)
- {
- int fds[2];
-
- pipe(fds);
- if (!fork()) {
- /* Read extra vehicles, and write them to the pipe.
- */
- int i=0;
- while(extras[i])
- nprintf(fds[1],"%s\n",extras[i++]);
- nprintf(fds[1],"end\n");
- exit(0);
- }
- else {
- readfile(&eohead,&evhead,fds[0],NULL);
- }
- printf("done reading extra vehicles\n");
- }
-
- /* Ejects the player from his/her current vehicle. */
- void eject(struct vehicle **vhead, struct object **ohead, struct vehicle *v)
- {
- struct vehicle *nv;
- struct point pos;
- int i;
-
- /* create a new vehicle structure */
- nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
- nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
- sizeof(struct object *));
- nv->next = *vhead;
- *vhead = nv;
-
- /* fill it in with a copy of the lifeform vehicle from the bullets file */
- copyvehicle(nv,findbycode(evhead,"player"),ohead);
- nv->code = strdupe("player");
- nv->velocity = 0;
- nv->owner = v->owner;
- nv->climb = 0;
- nv->alive = true;
- nv->vid = vidcount++;
- nv->target = -1;
- nv->reload = 0;
- nv->lock = -1;
- nv->res = v->res;
- nv->pnum = v->pnum;
-
- /* position the player near their old vehicle */
- pos = v->bmax;
- for(i=0; i<nv->partcount; i++) {
- nv->parts[i]->pos.x += pos.x+6;
- nv->parts[i]->pos.y += pos.y+6;
- nv->parts[i]->pos.z += (v->bmin.z > 0 ? v->bmin.z : 0);
- }
- calcbbox(nv);
- }
-
- /* returns true if a player f can enter the vehicle v.
- */
- bool enteredvehicle(struct vehicle *f, struct vehicle *v)
- {
- if ((f->owner == o_player || f->owner == o_network) &&
- v->owner == o_none && f->type == findbycode(evhead,"player")->type)
- return true;
- else
- return false;
- }
-
- /* rotatevehicle - rotate the given vehicle, and all it's parts.
- */
- void rotatevehicle(struct vehicle *v, double newang)
- {
- int i;
-
- for(i=0; i < v->partcount; i++)
- rotatez(v->parts[i],newang - v->angle);
- for(i=0; i<v->partcount; i++)
- if (v->parts[i]->turret)
- v->parts[i]->angle += (newang - v->angle);
- v->angle = newang;
- }
-
- /* calculates the square of the distance from vehicle v1 to v2. */
- float vehicledist(struct vehicle *v1, struct vehicle *v2)
- {
- float xd,yd,zd;
- struct point vp1,vp2;
-
- vp1 = v1->parts[0]->pos;
- vp2 = v2->parts[0]->pos;
- xd = vp1.x - vp2.x;
- yd = vp1.y - vp2.y;
- zd = vp1.z - vp2.z;
- return xd*xd + yd*yd + zd*zd;
- }
-
- /* calculates the altitude difference from v2 to v1 */
- double heightdiff(struct vehicle *v1, struct vehicle *v2)
- {
- return v1->parts[0]->pos.z - v2->parts[0]->pos.z;
- }
-
-